package com.um.swing.component;

import com.um.swing.dialog.JLoadDialog;
import com.um.swing.bean.ImageItem;
import com.um.swing.common.util.MathUtils;
import com.um.swing.common.inc.CreateCursor;
import com.um.swing.common.inc.Constant;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.function.Function;


/**
 * pview JPanel
 */
public class JImagePane extends JPanel {

    private static final long serialVersionUID = 7088737542307810259L;

    public static final int DEFAULT_WIDTH = 800;
    public static final int DEFAULT_HEIGHT = 600;
    public static final int ORIN_SIZE = 1;
    public static final int WIND_SIZE = 2;

    public static final float MAX_PERCENT = 1.5F;
    public static final float MIN_PERCENT = 0.02F;
    public static final float WHEEL_ZOOM_OFFSET = 0.02F;
    public static final float CLICK_ZOOM_OFFSET = 0.1F;

    //页面的内边距
    public static final int PADDING_NUM = 100;

    //滚动条
    public JScrollBar jScrollVbar = null;
    public JScrollBar jScrollHbar = null;


    private ImageItem curImageItem;
    private ImageIcon icon = null;
    private ImageIcon i_bak = null;
    private Double theta = 0D;//旋转
    private float percent = 1.0F;//缩放比例
    private Dimension orin_size = null;

    private int i_width, i_height;
    private int w_width, w_height;
    private Point point;
    private int x_val = -1, y_val = -1;
    private boolean wheel_lock = false;
    private TabGujiJoinPanel jTabGujiJoinPanel;

    private boolean mIsDrag = false;

    private static JImagePane __instance = null;

    public static JImagePane getInstance() {
        if (__instance == null)
            __instance = new JImagePane();
        return __instance;
    }

    public void setjScrollVbar(JScrollBar scrollVbar, JScrollBar scrollHbar) {
        this.jScrollVbar = scrollVbar;
        this.jScrollHbar = scrollHbar;
    }

    public void setjTabGujiJoinPanel(TabGujiJoinPanel jTabGujiJoinPanel) {
        this.jTabGujiJoinPanel = jTabGujiJoinPanel;
    }

    //回调事件
    private Function<ImageItem, Object> pointClickEvent;//定位点击事件

    public void setPointClickEvent(Function<ImageItem, Object> pointClickEvent) {
        this.pointClickEvent = pointClickEvent;
    }

    private JImagePane() {
        //this.setPreferredSize(new Dimension(2000, 3000));
        DragEventListener listener = new DragEventListener();
        this.addMouseListener(listener);
        this.addMouseMotionListener(listener);
        this.addMouseWheelListener(listener);
    }

    public void clear() {
        this.i_bak = null;
        this.curImageItem = null;
        this.repaint();
    }

    /**
     * picture drag handler inner class
     */
    private class DragEventListener extends MouseAdapter implements MouseMotionListener, MouseWheelListener {
        @Override
        public void mousePressed(MouseEvent e) {
            if (icon != null) {
                point = e.getLocationOnScreen();
                y_val = jScrollVbar.getValue();
                x_val = jScrollHbar.getValue();
            }
        }

        @Override
        public void mouseReleased(MouseEvent e) {
            if (icon == null) {
                return;
            }
            if (mIsDrag) {
                mIsDrag = false;
                setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
            } else if (curImageItem != null) {
                setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
                Point point = e.getPoint();
                //计算出相对图片的点位
                Component component = e.getComponent();
                int startX = component.getWidth() / 2 - (i_width / 2);
                int startY = component.getHeight() / 2 - (i_height / 2);

                //点击位置
                double clickX = point.getX();
                double clickY = point.getY();

                //边界限定，不允许点出图片外
                if (clickX < startX) {
                    clickX = startX;
                } else if (clickX > startX + i_width) {
                    clickX = startX + i_width;
                }
                if (clickY < startY) {
                    clickY = startY;
                } else if (clickY > startY + i_height) {
                    clickY = startY + i_height;
                }
                //相对原始图片的点击位置
                double relClickX = (clickX - startX) / percent;
                double relClickY = (clickY - startY) / percent;

                Point relClickPoint = new Point();
                relClickPoint.setLocation(relClickX, relClickY);

                curImageItem.putPointMapItem("p" + curImageItem.getPointIndex(), relClickPoint);
                curImageItem.setOldPointIndex(curImageItem.getPointIndex());
                if (curImageItem.getPointIndex() == 4) {
                    curImageItem.setPointIndex(1);
                } else {
                    curImageItem.setPointIndex(curImageItem.getPointIndex() + 1);
                }
                if (pointClickEvent != null) {
                    pointClickEvent.apply(curImageItem);
                }
                repaint();
            }
        }

        @Override
        public synchronized void mouseDragged(MouseEvent e) {
            mIsDrag = true;
            if (icon != null && point != null) {
                setCursor(CreateCursor.createIcon("move"));

                Point p = e.getLocationOnScreen();
                int x_offset = p.x - point.x;
                int y_offset = p.y - point.y;

                //check the vertical direction.
                if (y_offset > 0) {                //head down
                    if (jScrollVbar.getValue() > jScrollVbar.getMinimum()) {
                        int v = y_val - y_offset;
                        if (v < jScrollVbar.getMinimum())
                            v = jScrollVbar.getMinimum();
                        jScrollVbar.setValue(v);
                    }
                } else {                            //head up
                    if (jScrollVbar.getValue() < jScrollVbar.getMaximum()) {
                        int v = y_val - y_offset;
                        if (v > jScrollVbar.getMaximum())
                            v = jScrollVbar.getMaximum();
                        jScrollVbar.setValue(v);
                    }
                }

                //check the horizontal direction
                if (x_offset > 0) {                //head right
                    if (jScrollHbar.getValue() > jScrollHbar.getMinimum()) {
                        int v = x_val - x_offset;
                        if (v < jScrollHbar.getMinimum())
                            v = jScrollHbar.getMinimum();
                        jScrollHbar.setValue(v);
                    }
                } else {                            //head left
                    if (jScrollHbar.getValue() < jScrollHbar.getMaximum()) {
                        int v = x_val - x_offset;
                        if (v > jScrollHbar.getMaximum())
                            v = jScrollHbar.getMaximum();
                        jScrollHbar.setValue(v);
                    }
                }
            }
        }

        @Override
        public synchronized void mouseWheelMoved(MouseWheelEvent e) {
            if (wheel_lock == false && icon != null &&
                    e.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL
                /*&& ( e.isShiftDown() || e.isControlDown() )*/) {
                wheel_lock = true;

                if (e.getWheelRotation() < 0) {
                    larger(WHEEL_ZOOM_OFFSET);
                    wheel_lock = false;
//                    MainView.ThreadPoll.execute(new Runnable() {
//                        @Override
//                        public void run() {
//                            larger(WHEEL_ZOOM_OFFSET);
//                            wheel_lock = false;
//                        }
//                    });
                } else if (e.getWheelRotation() > 0) {
                    smaller(WHEEL_ZOOM_OFFSET);
                    wheel_lock = false;
//                    MainView.ThreadPoll.execute(new Runnable() {
//                        @Override
//                        public void run() {
//                            smaller(WHEEL_ZOOM_OFFSET);
//                            wheel_lock = false;
//                        }
//                    });
                } else {
                    wheel_lock = false;

                }
            }
        }
    }

    @Override
    public void paintComponent(Graphics g) {
        Graphics2D g2 = (Graphics2D) g;
        g2.setColor(Constant.PIC_DEFAULT_BG);
        g2.fillRect(0, 0, this.getWidth(), this.getHeight());

        if (i_bak != null && curImageItem != null) {

            int cWidth = this.getWidth() / 2;
            int cHeight = this.getHeight() / 2;
            g2.translate(cWidth, cHeight);
            //draw the image
            g2.rotate(Math.toRadians(theta));
            g.drawImage(i_bak.getImage(), -i_width / 2, -i_height / 2, i_width, i_height, null);

            if (!curImageItem.isPreview()) {
                //绘制点
                g.setColor(Color.RED);
                g2.setStroke(new BasicStroke(1.5f, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND));
                g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                for (int i = 1; i <= 4; i++) {
                    drawPoint(g2, curImageItem.getPointMapItem("p" + i), i);
                }

                Point p1 = curImageItem.getPointMapItem(ImageItem.P1);
                Point p2 = curImageItem.getPointMapItem(ImageItem.P2);
                Point p3 = curImageItem.getPointMapItem(ImageItem.P3);
                Point p4 = curImageItem.getPointMapItem(ImageItem.P4);

                //点1和点2要连一根线叫做L1
                if (p1 != null && p2 != null) {
                    p1 = calcDrawPoint(p1);
                    p2 = calcDrawPoint(p2);
//                drawPoint(g2, new Point(2000,2000), 200);

                    Point topLineP1 = new Point(-cWidth, -cHeight);
                    Point topLineP2 = new Point(cWidth, -cHeight);

                    Point bottomLineP1 = new Point(-cWidth, cHeight);
                    Point bottomLineP2 = new Point(cWidth, cHeight);

                    Point dP1 = MathUtils.getIntersectPoint(p1, p2, topLineP1, topLineP2);
                    Point dP2 = MathUtils.getIntersectPoint(p1, p2, bottomLineP1, bottomLineP2);

                    drawLine(g, dP1, dP2);

                    //点3要和L1连一个垂直的线
                    if (p3 != null) {
                        Point point = calcDrawPoint(p3);
                        Point footPoint = MathUtils.getFoot(p1, p2, point);
                        drawLine(g, footPoint, getBorderPoint(point, footPoint));
                    }
                    //点4要和L1连一个垂直的线
                    if (p4 != null) {
                        Point point = calcDrawPoint(p4);
                        Point footPoint = MathUtils.getFoot(p1, p2, point);
                        drawLine(g, footPoint, getBorderPoint(point, footPoint));
                    }
                }
            }
            JLoadDialog.getInstance().hiddenDialog();
        }
    }

    private void drawPoint(Graphics2D g2, Point point, int i) {
        if (point == null) return;
        int ovalWidth = 20;
        int ovalHeight = 20;
        Point targetPoint = calcDrawPoint(point);
        int targetX = targetPoint.x - ovalWidth / 2;
        int targetY = targetPoint.y - ovalHeight / 2;
        g2.drawOval(targetX, targetY, ovalWidth, ovalHeight);
        g2.drawString(String.valueOf(i), targetX + 25, targetY + 15);
        g2.setStroke(new BasicStroke(1f, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND));
        g2.drawLine(targetX, targetY + ovalHeight / 2, targetX + ovalWidth, targetY + ovalHeight / 2);
        g2.drawLine(targetX + ovalHeight / 2, targetY, targetX + ovalHeight / 2, targetY + ovalWidth);
    }

    //计算坐标：把相对图片原点坐标系的坐标转换成相对图片中心点坐标系的坐标
    private Point calcDrawPoint(Point point) {
        //相对组件的中心点坐标
        int centerX = this.getWidth() / 2;
        int centerY = this.getHeight() / 2;
        //相对组件的起始点坐标
        int startX = centerX - (i_width / 2);
        int startY = centerY - (i_height / 2);
        //相对组件的点击点坐标 （相对起始点的坐标+起始点坐标）
        int x = (int) (point.x * percent) + startX;
        int y = (int) (point.y * percent) + startY;
        return new Point(x - centerX, y - centerY);
    }

    //获取线段到边框的交点
    private Point getBorderPoint(Point p3, Point footPoint) {
        Point borderPointP1;
        Point borderPointP2;

        int cWidth = this.getWidth() / 2;
        int cHeight = this.getHeight() / 2;

        if (p3.getX() > footPoint.getX()) {
            borderPointP1 = new Point(cWidth, -cHeight);
            borderPointP2 = new Point(cWidth, cHeight);
        } else {
            borderPointP1 = new Point(-cWidth, -cHeight);
            borderPointP2 = new Point(-cWidth, cHeight);
        }
        Point intersectPoint2 = MathUtils.getIntersectPoint(p3, footPoint, borderPointP1, borderPointP2);
        return intersectPoint2;
    }

    /**
     * @param g
     * @param cWidth
     * @param cHeight
     * @param p3
     * @param footPoint
     */
    private void drawLine(Graphics g, Point p1, Point p2) {
        int cWidth = this.getWidth() / 2;
        int cHeight = this.getHeight() / 2;
        if (p1 == null || p2 == null) {
            return;
        }
        try {
            int lineP1X = (int) (p1.getX() /*- cWidth*/);
            int lineP1Y = (int) (p1.getY() /*- cHeight*/);
            int lineP2X = (int) (p2.getX() /*- cWidth*/);
            int lineP2Y = (int) (p2.getY() /*- cHeight*/);
            g.drawLine(lineP1X, lineP1Y, lineP2X, lineP2Y);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void drawPicture(ImageIcon __src, ImageItem item) {
        resetWindSizeFlag(orin_size != null ? ORIN_SIZE : WIND_SIZE);
        icon = __src;
        curImageItem = item;
        theta = 0D;
        if (item.isPreview()) {
            percent = 1.0F;
        }
        re_count();
        if (i_bak != null) {
            setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
        }
        repaint();
    }

    public void rotateLeft() {
        if (icon != null) {
            JLoadDialog.getInstance().showDialog();
            synchronized (jTabGujiJoinPanel.LOCK) {
                resetWindSizeFlag(ORIN_SIZE);
                percent = 1.0F;
                theta += -90;
                if (theta == -360) theta = 0D;
                re_count();
                selfRepaint();
            }
        }
    }

    public void rotateRight() {
        if (icon != null) {
            JLoadDialog.getInstance().showDialog();
            synchronized (jTabGujiJoinPanel.LOCK) {
                resetWindSizeFlag(ORIN_SIZE);
                percent = 1.0F;
                theta += 90;
                if (theta == 360) theta = 0D;
                re_count();
                selfRepaint();
            }
        }
    }

    public void larger(float offset) {
        if (icon != null && percent < MAX_PERCENT) {
            JLoadDialog.getInstance().showDialog();
            synchronized (jTabGujiJoinPanel.LOCK) {
                percent += offset;
                if (percent > MAX_PERCENT)
                    percent = MAX_PERCENT;
                re_count();
                selfRepaint();
                centerScrollPane();
            }
        }
    }

    public void setZoom(float zoom) {
        if (zoom < 0) {
            resetWindSizeFlag(ORIN_SIZE);
        } else {
            this.percent = zoom;
        }
        if (icon != null) {
            if (percent > MAX_PERCENT)
                percent = MAX_PERCENT;
            re_count();
            repaint();
//            centerScrollPane();
        }
    }

    public float getZoom() {
        return percent;
    }


    public void smaller(float offset) {
        if (icon != null && percent > MIN_PERCENT) {
            JLoadDialog.getInstance().showDialog();
            synchronized (jTabGujiJoinPanel.LOCK) {
                percent -= offset;
                if (percent < MIN_PERCENT)
                    percent = MIN_PERCENT;
                re_count();
                selfRepaint();
                centerScrollPane();
            }
        }
    }

    public void centerScrollPane() {
        jScrollVbar.setValue(jScrollVbar.getMaximum() / 4);
        jScrollHbar.setValue(jScrollHbar.getMaximum() / 4);

    }

    public void self() {
        if (icon != null) {
            JLoadDialog.getInstance().showDialog();
            synchronized (jTabGujiJoinPanel.LOCK) {
                resetWindSizeFlag(ORIN_SIZE);
                theta = 0D;
                percent = 1.0F;
                re_count();
                selfRepaint();
            }
        }
    }

    public void setPaneSize(Dimension size) {
        if (size != null) {
            setPreferredSize(new Dimension(size.width - 25, size.height - 30));
            setSize(size);
        }
    }

    public void selfRepaint() {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                repaint();
            }
        });
    }

    public void re_count() {
        if (icon == null) return;
        i_width = icon.getIconWidth();
        i_height = icon.getIconHeight();
        float wbit = (float) w_width / icon.getIconWidth();
        float hbit = (float) w_height / icon.getIconHeight();

        if (theta < 0) theta += 360;
        if (theta == 90 || theta == 270) {
            wbit = (float) w_width / icon.getIconHeight();
            hbit = (float) w_height / icon.getIconWidth();
            //width = icon.getIconHeight();
            //height = icon.getIconWidth();
        }

        boolean isOne = false;

        if (percent == 1.0F && (wbit < 1 || hbit < 1)) {
            percent = Math.min(wbit, hbit);
            orin_size = new Dimension(w_width, w_height);
            isOne = true;
        }
        jTabGujiJoinPanel.setPercent(percent);
        i_width = (int) (i_width * percent);
        i_height = (int) (i_height * percent);

        //get the scaled image
        i_bak = new ImageIcon(icon.getImage()
                .getScaledInstance(i_width, i_height, Image.SCALE_FAST));

        //update the size of image pane
        this.setPaneSize(
                new Dimension(
                        Math.max(w_width, i_width) + PADDING_NUM,
                        Math.max(w_height, i_height) + PADDING_NUM
                )
        );
    }

    public void resetOrinSize(int w, int h) {
        orin_size = new Dimension(w, h);
    }

    public void resetWindSizeFlag(int flag) {
        if (flag == ORIN_SIZE) {
            w_width = orin_size.width;
            w_height = orin_size.height;
        } else if (flag == WIND_SIZE) {
            w_width = this.getWidth();
            w_height = this.getHeight();
        }
    }
}
